package com.baoteng.rbspy.service.impl;

import java.io.IOException;
import java.net.SocketTimeoutException;

import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mustache.MustacheResourceTemplateLoader;
import org.springframework.stereotype.Service;

import com.baoteng.rbspy.config.car.RbSysConfig;
import com.baoteng.rbspy.config.car.URLConfig;
import com.baoteng.rbspy.interceptor.cookie.OKHttpCookieJar;
import com.baoteng.rbspy.model.Model;
import com.baoteng.rbspy.model.login.LoginPO;
import com.baoteng.rbspy.model.renewal.RenewalPO;
import com.baoteng.rbspy.model.request.RenewalRequest;
import com.baoteng.rbspy.model.response.ResponseModel;
import com.baoteng.rbspy.service.OkHttpClientService;
import com.baoteng.rbspy.util.JsonUtils;
import com.baoteng.rbspy.util.JsoupUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.samskivert.mustache.Mustache;

import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

@Service(value="okHttpClientService")
public class OkHttpClientServiceImpl implements OkHttpClientService {

	private final Logger LOGGER = LoggerFactory.getLogger(OkHttpClientService.class);

	@Autowired
	protected OkHttpClient okHttpsClient;

	@Autowired
	RbSysConfig rbSysConfig;
	
	@Autowired
	URLConfig urlConfig;

	@Autowired
	private Mustache.Compiler compiler;

	@Autowired
	MustacheResourceTemplateLoader mustacheTemplateLoader;

	@Override
	public boolean logout() {
		ResponseModel<LoginPO> logoutResponse = getHtml(rbSysConfig.getLogoutUrl(), LoginPO.class);
		if (logoutResponse.isSuccessful()) {
			OKHttpCookieJar.Builder bulder = new OKHttpCookieJar.Builder();
			bulder.removeCookie(rbSysConfig.getLogoutUrl()).removeCookie(urlConfig.getLoginUrl()).removeCookie(urlConfig.getCifUrl());
			return true;
		}
		return false;
	}

	/**
	 * 登陆核心业务系统
	 */
	@Override
	public boolean login() {
		ResponseModel<LoginPO> indexResponse = getHtml(rbSysConfig.getLoginUrl(), LoginPO.class);
		if (indexResponse.isSuccessful() && indexResponse.getBody() != null
				&& StringUtils.isNotBlank(indexResponse.getBody().getLtToken())) {
			FormBody.Builder bodyBuilder = new FormBody.Builder();
			bodyBuilder.add("PTAVersion", "");
			bodyBuilder.add("toSign", "");
			bodyBuilder.add("Signature", "");
			bodyBuilder.add("rememberFlag", "0");
			bodyBuilder.add("userMac", "");
			bodyBuilder.add("key", "yes");
			bodyBuilder.add("errorKey", "null");
			bodyBuilder.add("loginMethod", "nameAndPwd");
			bodyBuilder.add("username", rbSysConfig.getLoginUser());
			bodyBuilder.add("password", rbSysConfig.getLoginPwd());
			bodyBuilder.add("lt", indexResponse.getBody().getLtToken().trim());
			bodyBuilder.add("_eventId", "submit");
			bodyBuilder.add("pcguid", "");
			bodyBuilder.add("button.x", "13");
			bodyBuilder.add("button.y", "13");
			if(StringUtils.isNotBlank(rbSysConfig.getUserMac()))  bodyBuilder.add("userMac", rbSysConfig.getUserMac());
			ResponseModel<LoginPO> loginResponse = postHtml(rbSysConfig.getLoginUrl(), bodyBuilder.build(), LoginPO.class);
			return loginResponse.isSuccessful();
		}
		return false;
	}

	/**
	 * 登陆车险系统
	 */
	@Override
	public boolean carlogin() {
		if(!isOnline()) login();
		ResponseModel<String> carLoginResponse = getHtml(urlConfig.getLoginUrl(), String.class);
		return carLoginResponse.isSuccessful();
	}

	/**
	 * 登陆客户管理系统
	 */
	@Override
	public boolean ciflogin() {
		if(!isOnline()) login();
		ResponseModel<String> carLoginResponse = getHtml(urlConfig.getCifUrl(), String.class);
		return carLoginResponse.isSuccessful();
	}

	/**
	 * 登陆见费出单系统
	 */
	@Override
	public boolean cbclogin() {
		if(!isOnline()) login();
		ResponseModel<String> carLoginResponse = getHtml(urlConfig.getCbcUrl(), String.class);
		return carLoginResponse.isSuccessful();
	}
	
//	@Override
//	public boolean isOnline() {
//		RenewalRequest request = new RenewalRequest();
//		request.setLicenseNo("粤AHS598");
//		request.setLicenseType("02");
//		String strBody;
//		try {
//			strBody = compiler.compile(mustacheTemplateLoader.getTemplate("renewal")).execute(request);
//			ResponseModel<Model<RenewalPO>> onlineResponse = postJson(urlConfig.getRenewalUrl(), strBody,
//					new TypeReference<Model<RenewalPO>>() {
//					});
//			return onlineResponse.isSuccessful() && onlineResponse.getBody() != null ;
//		} catch (Exception e) {
//			LOGGER.error("rbspy isOnline fail.", e);
//		}
//		return false;
//	}

	@Override
	public boolean isOnline() {
		try {
			RenewalRequest request = new RenewalRequest();
			request.setLicenseNo("粤AHS598");
			request.setLicenseType("02");
			String strBody;
			strBody = compiler.compile(mustacheTemplateLoader.getTemplate("renewal")).execute(request);
			ResponseModel<Model<RenewalPO>> renewalResponse = postJson(urlConfig.getRenewalUrl(), strBody,
						new TypeReference<Model<RenewalPO>>() {
						});
			if(!renewalResponse.isSuccessful() || renewalResponse.getBody()==null || renewalResponse.getBody().getData()==null 
					|| renewalResponse.getBody().getData().isEmpty()) {
				return false;
			}
			ResponseModel<String> onlineResponse = getHtml(urlConfig.getIndexURL(), 
					String.class);
			if(onlineResponse.isSuccessful() && StringUtils.isNotBlank(onlineResponse.getBody())) {
				Elements elements = Jsoup.parse(onlineResponse.getBody()).select("#mainFrame");
				return elements!=null && elements.size()>0 ;
			}
			
		} catch (Exception e) {
			LOGGER.error("rbspy isOnline fail.", e);
		}
		return false;
	}
	
	@Override
	public boolean isCarOnline() {
		RenewalRequest request = new RenewalRequest();
		request.setLicenseNo("粤AHS598");
		request.setLicenseType("02");
		String strBody;
		try {
			strBody = compiler.compile(mustacheTemplateLoader.getTemplate("renewal")).execute(request);
			ResponseModel<Model<RenewalPO>> onlineResponse = postJson(urlConfig.getRenewalUrl(), strBody,
					new TypeReference<Model<RenewalPO>>() {
					});
			return onlineResponse.isSuccessful() && onlineResponse.getBody() != null;
		} catch (Exception e) {
			LOGGER.error("rbspy isOnline fail.", e);
		}
		return false;
	}

	@Override
	public boolean isCifOnline() {
		RenewalRequest request = new RenewalRequest();
		request.setLicenseNo("粤AHS598");
		request.setLicenseType("02");
		String strBody;
		try {
			strBody = compiler.compile(mustacheTemplateLoader.getTemplate("renewal")).execute(request);
			ResponseModel<Model<RenewalPO>> onlineResponse = postJson(urlConfig.getRenewalUrl(), strBody,
					new TypeReference<Model<RenewalPO>>() {
					});
			return onlineResponse.isSuccessful() && onlineResponse.getBody() != null;
		} catch (Exception e) {
			LOGGER.error("rbspy isOnline fail.", e);
		}
		return false;
	}

	@Override
	public <T> ResponseModel<T> getJson(String url, TypeReference<T> typeReference) {
		ResponseModel<T> _response = new ResponseModel<T>();
		_response.setCode("503");
		Request request = null;
		try {
			request = new Request.Builder().url(url).build();
			Response response = okHttpsClient.newCall(request).execute();
			_response = jsonParser(_response, response, typeReference);
		} catch (IOException e1) {
			exceptionHandler(e1,request,"httpclient getJson error",_response,typeReference);
		}
		return _response;
	}

	@Override
	public <T> ResponseModel<T> postJson(String url, String content, TypeReference<T> typeReference) {
		ResponseModel<T> _response = new ResponseModel<T>();
		_response.setCode("503");
		Request request = null;
		try {
			if(content!=null ) content = content.replaceAll("(\r\n|\r|\n|\n\r)", "");
			request = new Request.Builder()
					.url(url).post(RequestBody
							.create(MediaType.parse("application/x-www-form-urlencoded; charset=UTF-8"), content))
					.build();
			Response response = okHttpsClient.newCall(request).execute();
			_response = jsonParser(_response, response, typeReference);
		} catch (IOException e) {
			exceptionHandler(e,request,"httpclient postJson error",_response,typeReference);
		} 

		return _response;
	}

	@Override
	public <T> ResponseModel<T> postJson(String url, RequestBody body, TypeReference<T> typeReference) {
		ResponseModel<T> _response = new ResponseModel<T>();
		_response.setCode("503");
		Request request = null;
		try {
			request = new Request.Builder().url(url).post(body).build();
			Response response = okHttpsClient.newCall(request).execute();
			_response = jsonParser(_response, response, typeReference);
		} catch (IOException e) {
			exceptionHandler(e,request,"httpclient postJson error",_response,typeReference);
		}

		return _response;
	}

	private <T> ResponseModel<T> jsonParser(ResponseModel<T> _response, Response response,
			TypeReference<T> typeReference) {
		try {
			if (response != null && response.isSuccessful()) {
				_response.setCode("200");
				String strBody = response.body().string();
				if (StringUtils.isNotBlank(strBody)) {
					strBody = strBody.trim();
					if (strBody.startsWith("{") || strBody.startsWith("[")) {
						LOGGER.info(strBody);
						_response.setBody(JsonUtils.parseJson(strBody, typeReference));
					} else {
						_response.setBody(null);
					}
				}
			}else {
				_response.setCode(response!=null?String.valueOf(response.code()):"500");
			}
		} catch (IOException e) {
			LOGGER.error("httpclient jsonParser error", e);
			_response.setCode("500");
		}
		return _response;
	}

	@Override
	public <T> ResponseModel<T> getHtml(String url, Class<T> clazz) {
		ResponseModel<T> _response = new ResponseModel<T>();
		_response.setCode("503");
		Request request = null;
		try {
			request = new Request.Builder().url(url).build();
			Response response = okHttpsClient.newCall(request).execute();
			_response = htmlParser(_response, response, clazz);
		} catch (IOException e) {
			exceptionHandler(e,request,"httpclient getHtml error",_response,clazz);
		}

		return _response;
	}

	@Override
	public <T> ResponseModel<T> postHtml(String url, String content, Class<T> clazz) {
		ResponseModel<T> _response = new ResponseModel<T>();
		_response.setCode("503");
		Request request = null;
		try {
			if(content!=null ) content = content.replaceAll("\r\n|\r|\n|\n\r", "");
			request = new Request.Builder()
					.url(url).post(RequestBody
							.create(MediaType.parse("application/x-www-form-urlencoded; charset=UTF-8"), content))
					.build();
			Response response = okHttpsClient.newCall(request).execute();
			_response = htmlParser(_response, response, clazz);
		} catch (IOException e) {
			LOGGER.error("httpclient postHtml error", e);
			_response.setCode("500");
			exceptionHandler(e,request,"httpclient postHtml error",_response,clazz);
		}

		return _response;
	}

	@Override
	public <T> ResponseModel<T> postHtml(String url, RequestBody body, Class<T> clazz) {
		ResponseModel<T> _response = new ResponseModel<T>();
		_response.setCode("503");
		Request request = null;
		try {
			request = new Request.Builder().url(url).post(body).build();
			Response response = okHttpsClient.newCall(request).execute();
			_response = htmlParser(_response, response, clazz);
		} catch (IOException e) {
			exceptionHandler(e,request,"httpclient postHtml error",_response,clazz);
		}

		return _response;
	}

	@SuppressWarnings("unchecked")
	private <T> ResponseModel<T> htmlParser(ResponseModel<T> _response, Response response, Class<T> clazz) {
		try {
			if (response != null && response.isSuccessful()) {
				_response.setCode("200");
				String strBody = response.body().string();
				if (StringUtils.isNotBlank(strBody)) {
					LOGGER.info(strBody);
					T t = clazz.newInstance();
					if (t instanceof String) {
						_response.setBody((T) strBody.trim());
					} else {
						if (strBody.contains("<html")) {
							_response.setBody((T) JsoupUtil.newInstance().parse(Jsoup.parse(strBody.trim()), t));
						} else {
							_response.setBody(null);
						}
					}
				}
			}else {
				_response.setCode(response!=null?String.valueOf(response.code()):"500");
			}
		} catch (InstantiationException | IllegalAccessException | IOException e) {
			LOGGER.error("httpclient htmlParser error", e);
			_response.setCode("500");
		}
		return _response;
	}
	
	/**
	 * 简单处理readtimeout，重试一次
	 * @param e
	 * @param request
	 * @param errorMsg
	 * @param _response
	 * @param typeReference
	 */
	private <T> void exceptionHandler(IOException e,Request request,String errorMsg,ResponseModel<T> _response,TypeReference<T> typeReference) {
		if(e instanceof SocketTimeoutException && request!=null) {
			try {
				Response response = okHttpsClient.newCall(request).execute();
				_response = jsonParser(_response, response, typeReference);
				return ;
			} catch (IOException e1) {
				LOGGER.error(errorMsg, e1);
			}
		}else {
			LOGGER.error(errorMsg, e);
		}
		_response.setCode("500");
	}

	private <T> void exceptionHandler(IOException e,Request request,String errorMsg,ResponseModel<T> _response,Class<T> clazz) {
		if(e instanceof SocketTimeoutException && request!=null) {
			try {
				Response response = okHttpsClient.newCall(request).execute();
				_response = htmlParser(_response, response, clazz);
				return ;
			} catch (IOException e1) {
				LOGGER.error(errorMsg, e1);
			}
		}else {
			LOGGER.error(errorMsg, e);
		}
		_response.setCode("500");
	}
	
}
